package com.china.produce.controller;

import com.china.produce.annotation.Log;
import com.china.produce.service.UserService;
import com.china.produce.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.sql.SQLException;

/**
 * @ClassName
 * @Author niujie
 * @Version
 * @Description
 * @CreateTime 2022/7/3
 */
@Slf4j
@RequestMapping("/transaction")
@RestController
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class TransactionalController {

    @Autowired
    private UserService userService;

    @GetMapping("/test/{account}/{mobile}")
    @Transactional
    @Log
    public void test(@PathVariable("account") String account, @PathVariable("mobile") String mobile) {

        log.info("account : {} mobile : {}", account, mobile);

        userService.updateUserByName(account, mobile);

       // userService.queryUserByName(account);
    }

    @PostMapping("/testTransactional")
    @Transactional(value = "userReadManager", rollbackFor = Exception.class)
    public String testTransactional(@RequestBody UserVo userVo) {

        log.info("userVo {}", userVo);

        userService.insertUser(userVo.getAccount(), userVo.getPassword());

        TransactionalController aop = (TransactionalController) AopContext.currentProxy();

        aop.second(userVo.getAccount(), userVo.getPassword());

        int i = 10 / 0;

        return "success";
    }

    /**
     * REQUIRES_NEW的内部事务的异常，会影响外部事务的回滚;
     *
     * 标志REQUIRES_NEW会新开启事务，外层事务不会影响内部事务的提交/回滚
     *
     * @param account
     * @param password
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public String second(String account, String password) {
        userService.insertUser(account + "-",  password);

        return "success";
    }

    @PostMapping("/testTransactional2")
    @Transactional
    public String testTransactional2() throws Exception {

        TransactionalController tr = (TransactionalController) AopContext.currentProxy();

        tr.transaction1();

        tr.transactional2();

        return "success";
    }

    @Transactional(rollbackFor = Exception.class)
    public void transaction1() throws Exception {
        //事务抛出异常必须是RuntimeException才能被transactional接管，不然的话要添加rollbackFor的类型才会回滚
        try {
            UserVo userVo = new UserVo();
            userVo.setAccount("test");
            userVo.setPassword("123456");
            userService.insertUser(userVo.getAccount(), userVo.getPassword());
           // int j = 10 / 0;
        }catch (Exception exception) {
            throw new Exception(exception.getMessage());
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void transactional2() throws Exception {

        try {
            UserVo userVo = new UserVo();
            userVo.setAccount("test2");
            userVo.setPassword("0000");

            userService.insertUser(userVo.getAccount(), userVo.getPassword());

            int i = 10 / 0;
        }catch (Exception exception) {
            throw new Exception(exception.getMessage());
        }
    }

    @PostMapping("/testTransactional3")
    @Transactional
    public String testTransactional3() throws Exception {

        TransactionalController tr = (TransactionalController) AopContext.currentProxy();

        try {
            tr.transaction3();
        }catch (Exception exception) {

        }
        return "success";
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void transaction3() throws Exception {
        //事务抛出异常必须是RuntimeException才能被transactional接管，不然的话要添加rollbackFor的类型才会回滚
        try {
            UserVo userVo = new UserVo();
            userVo.setAccount("test3");
            userVo.setPassword("123456");
            userService.insertUser(userVo.getAccount(), userVo.getPassword());
            int j = 10 / 0;
        }catch (Exception exception) {
            throw new Exception(exception.getMessage());
        }
    }
}
